package org.andao.commons.taglib.ui;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;

import org.andao.commons.cache.CacheAppManager;
import org.andao.commons.taglib.BaseTagSupport;
import org.andao.commons.web.FileUriContext;
import org.andao.core.config.ConfigPropertyReader;
import org.andao.core.utils.ExStringUtils;


/**
 * 文件上传标签 支持IE8+,Chrome,FF等
 * <p>
 * 对于支持HTML5的浏览器，使用HTML5实现（dropzone.js插件），支持拖拽上传
 * <p>
 * 对于不支持HTML5的浏览器，使用flash实现（uploadify.js插件）
 * 
 * @author Seewo Software - Vick.liu (liuguanglin@cvte.cn)
 * 
 */
public class FileUploadTag extends BaseTagSupport {

	private static final long serialVersionUID = -5327086681601918917L;

	private static final String FILE_EXT_SPLIT_SEPORATOR = "\\|";// 文件后缀名分隔符："\|"，用于做str.split()的，因|是转义符
	private static final String FILE_EXT_SEPORATOR = "|";// 文件后缀名分隔符："|"

	private String url = CacheAppManager.getSysConfigurationByCode("web.uploadfile.mapping.save").getParamValue();// 提交路径(处理上传文件的controller
																													// url)

	private String deleteUrl = CacheAppManager.getSysConfigurationByCode("web.uploadfile.mapping.delete").getParamValue();// 提交路径(处理删除文件的controller
																															// url)

	private String theme = "basic";// 样式主题：basic|simple（basic是带预览功能，simple是没有预览功能，比较小，选择simple时，采用swf的方式上传。默认basic）

	private String baseStorePath;// 基本的存储路径(请使用,间隔)，如果是图片，则表示为图片的显示根路径

	private String extendStorePath;// 扩展的存储路径

	private String fileExt = CacheAppManager.getSysConfigurationByCode("web.uploadfile.accept").getParamValue();// 支持的附件格式，默认取系统配置的附件类型

	private String fileSize = CacheAppManager.getSysConfigurationByCode("web.uploadfile.filesize").getParamValue();// 允许上传的附件大小，默认去系统配置附件大小

	private String isMulti = "true";// 是否允许上传多个文件，默认允许

	private Integer uploadLimit = 10;// 允许上传的文件个数

	private String hiddenInputName = "uploadfileid";// 附件ID隐藏域名,如果为上次图片是，则传入图片路径字段名

	private String replaceName;// 附件替代名

	private String uploadType = "attach";// attach-附件 image -
											// 图片；如果是attach，则返回的id是attach.getResourceid();如果是图片，则返回的id是attach.getSername();

	private String oldImagePath;// 原有图片地址，用于图片上传时，对旧图片的预览。仅当theme="simple"&&uploadType="image"的时候生效

	// fields below are unknown and deprecated
	// only to support the old API of {@link SysFileManageController}
	private String formType;// 表单类型
	private String formId;// 表单ID
	private String isStoreToDatabase;// 是否需要存数据库 Y|N

	@Override
	public int doEndTag() throws JspException {
		String timeToken = "uploader_" + System.currentTimeMillis();

		// 过滤不合格的文件类型设置，只允许系统设置的子集
		fileExt = filterCustomFileExt(fileExt, CacheAppManager.getSysConfigurationByCode("web.uploadfile.accept").getParamValue());

		StringBuffer options = buildOptions();
		StringBuffer formData = buildFormData();

		// 设置隐藏域，用于上传提交的额外数据
		options.append(",optionHiddens:{" + formData + "}");

		options.append(",selector:'#" + timeToken + "'");

		String script = "<div class='upload-container'><div class='dz-upload-container' id=" + timeToken + " > <script type='text/javascript'>SC.Util.upload({" + options.toString() + "});</script> </div></div>";

		JspWriter writer = this.pageContext.getOut();
		try {
			writer.append(script);
		} catch (IOException e) {

		}
		return EVAL_PAGE;
	}

	/**
	 * 设置组件参数
	 * 
	 * @return
	 * @author Seewo Software - Vick.liu (liuguanglin@cvte.cn)
	 */
	private StringBuffer buildOptions() {
		StringBuffer options = new StringBuffer("hiddenInputName:'" + hiddenInputName + "'");

		if (ExStringUtils.isNotBlank(isMulti) && "false".equalsIgnoreCase(isMulti)) {
			options.append(",isMulti:'" + isMulti + "'");
			options.append(",uploadLimit:'" + 1 + "'");
			// 如果不能同时上传多个，则uploadLimit = 1
		} else {
			options.append(",uploadLimit:'" + uploadLimit + "'");
		}
		// 设置options属性
		options.append(",url:'" + getBaseUrl() + url.trim() + "'");
		options.append(",deleteUrl:'" + getBaseUrl() + deleteUrl + "'");
		options.append(",theme:'" + theme + "'");
		options.append(",uploadType:'" + uploadType + "'");
		options.append(",fileSize:'" + fileSize + "'");
		options.append(",fileExt:'" + fileExt + "'");// script使用
		oldImagePath = getServerOldImagePath();
		options.append(",oldImagePath:'" + oldImagePath + "'");

		// 服务器存储路径
		options.append(",rootPath:'" + FileUriContext.instance().getDownloadUrl(getrequest()) + "'");
		options.append(",tempPath:'" + FileUriContext.instance().getServerStoreTempPath().replace(FileUriContext.instance().getServerStoreRootPath(), "") + "'");

		return options;
	}

	/**
	 * 设置隐藏域，用于上传提交的额外数据
	 * 
	 * @return
	 * @author Seewo Software - Vick.liu (liuguanglin@cvte.cn)
	 */
	private StringBuffer buildFormData() {
		StringBuffer formData = new StringBuffer("storePath:'" + getStorePath() + "'");
		// 携带参数
		if (ExStringUtils.isNotBlank(formType)) {
			formData.append(",formType:'" + formType + "'");
		}
		if (ExStringUtils.isNotBlank(formId)) {
			formData.append(",formId:'" + formId + "'");
		}
		if (ExStringUtils.isNotBlank(isStoreToDatabase)) {
			formData.append(",isStoreToDatabase:'" + isStoreToDatabase + "'");
		}
		if (ExStringUtils.isNotBlank(replaceName)) {
			formData.append(",replaceName:'" + replaceName + "'");
		}

		// 携带jsessionid用于解决uploadify在firefox下session失效问题。
		formData.append(",jsessionid:'" + readCookies(getrequest(), "JSESSIONID") + "'");

		formData.append(",fileExt:'" + fileExt + "'");
		return formData;
	}

	/**
	 * 获取基本存储路径
	 * 
	 * @return
	 * @author Seewo Software - Vick.liu (liuguanglin@cvte.cn)
	 */
	private String getStorePath() {
		String storePath = (baseStorePath == null ? "" : baseStorePath);
		if (ExStringUtils.isNotBlank(extendStorePath)) {
			storePath = storePath + "," + extendStorePath;
		}
		return storePath;
	}

	/**
	 * 获取原有图片路径在服务器的相对路径
	 * 
	 * @return
	 * @author Seewo Software - Vick.liu (liuguanglin@cvte.cn)
	 */
	private String getServerOldImagePath() {
		if (ExStringUtils.isBlank(oldImagePath)) {
			return FileUriContext.instance().getWebContextUrl(getrequest()) + "/" + ConfigPropertyReader.getInstance().getProperty("web.ui.image.user");
		} else {
			return FileUriContext.instance().getDownloadUrl(getrequest()) + "/" + getStorePath().replaceAll(",", "/") +"/" + oldImagePath;
		}
	}

	/**
	 * 过滤不存在filter中的customFileExt,如filter="jpg|png";customFileExt="exe|jpg";
	 * 则return "jpg";
	 * 
	 * @param customFileExt
	 *            要被过滤的项目
	 * @param filter
	 *            允许的项
	 * @return
	 * @author Seewo Software - Vick.liu (liuguanglin@cvte.cn)
	 */
	private String filterCustomFileExt(String customFileExt, String filter) {
		String[] exts = customFileExt.split(FILE_EXT_SPLIT_SEPORATOR);
		StringBuilder realAcceptExtBuilder = new StringBuilder();
		boolean hasAccepted = false;
		for (String ext : exts) {
			if (filter.contains(ext)) {
				hasAccepted = true;// 存在一个合格的项
				realAcceptExtBuilder.append(ext);
				realAcceptExtBuilder.append(FILE_EXT_SEPORATOR);
			}
		}
		if (hasAccepted) {
			realAcceptExtBuilder.deleteCharAt(realAcceptExtBuilder.length() - 1);
		}
		return realAcceptExtBuilder.toString();
	}

	/**
	 * 根据key值读取cookie
	 * 
	 * @param request
	 * @param key
	 * @return
	 */
	private String readCookies(HttpServletRequest request, String key) {
		String value = null;
		if (key != null) {
			Cookie cookies[] = request.getCookies();
			for (int i = 0; cookies != null && i < cookies.length; i++) {
				Cookie cookie = cookies[i];
				if (ExStringUtils.equals(cookie.getName(), key)) {
					value = cookie.getValue();
					break;
				}
			}
		}
		try {
			if (ExStringUtils.isNotEmpty(value)) {
				value = URLDecoder.decode(value, "UTF-8");
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return value;
	}

	/***************** setter and getter ******************/

	public String getBaseStorePath() {
		return baseStorePath;
	}

	public void setBaseStorePath(String baseStorePath) {
		this.baseStorePath = baseStorePath;
	}

	public String getExtendStorePath() {
		return extendStorePath;
	}

	public void setExtendStorePath(String extendStorePath) {
		this.extendStorePath = extendStorePath;
	}

	public String getFileExt() {
		return fileExt;
	}

	public void setFileExt(String fileExt) {
		this.fileExt = fileExt;
	}

	public String getFileSize() {
		return fileSize;
	}

	public void setFileSize(String fileSize) {
		this.fileSize = fileSize;
	}

	public String getIsMulti() {
		return isMulti;
	}

	public void setIsMulti(String isMulti) {
		this.isMulti = isMulti;
	}

	public Integer getUploadLimit() {
		return uploadLimit;
	}

	public void setUploadLimit(Integer uploadLimit) {
		this.uploadLimit = uploadLimit;
	}

	public String getUploadType() {
		return uploadType;
	}

	public void setUploadType(String uploadType) {
		this.uploadType = uploadType;
	}

	public String getReplaceName() {
		return replaceName;
	}

	public void setReplaceName(String replaceName) {
		this.replaceName = replaceName;
	}

	public String getHiddenInputName() {
		return hiddenInputName;
	}

	public void setHiddenInputName(String hiddenInputName) {
		this.hiddenInputName = hiddenInputName;
	}

	public String getFormType() {
		return formType;
	}

	public void setFormType(String formType) {
		this.formType = formType;
	}

	public String getFormId() {
		return formId;
	}

	public void setFormId(String formId) {
		this.formId = formId;
	}

	public String getIsStoreToDatabase() {
		return isStoreToDatabase;
	}

	public void setIsStoreToDatabase(String isStoreToDatabase) {
		this.isStoreToDatabase = isStoreToDatabase;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getTheme() {
		return theme;
	}

	public void setTheme(String theme) {
		this.theme = theme;
	}

	public String getDeleteUrl() {
		return deleteUrl;
	}

	public void setDeleteUrl(String deleteUrl) {
		this.deleteUrl = deleteUrl;
	}

	public String getOldImagePath() {
		return oldImagePath;
	}

	public void setOldImagePath(String oldImagePath) {
		this.oldImagePath = oldImagePath;
	}

}
